﻿using System;
using System.Linq;
using System.Windows;
using LINQPad.OpenAccess.Helpers;
using LINQPad.OpenAccess.UI.Events;
using LINQPad.OpenAccess.UI.ViewModel;

namespace LINQPad.OpenAccess.UI.Adapters
{
    /// <summary>
    /// Simple window adapter used to handle the close requests from the view model.
    /// </summary>
    public sealed class WindowAdapter : IDisposable
    {
        #region Private

        #region - Vars

        private bool _ownsViewModel;

        #endregion

        #region - Functions

        /// <summary>
        /// Hooks the view model events.
        /// </summary>
        /// <param name="viewModel">The view model.</param>
        private void HookViewModelEvents( DriverSettingsViewModel viewModel )
        {
            viewModel.CloseViewRequested += ViewModel_CloseViewRequested;
        }
        /// <summary>
        /// Hooks the window events.
        /// </summary>
        /// <param name="window">The window.</param>
        private void HookWindowEvents( Window window )
        {
            window.Closed += Window_Closed;
        }
        /// <summary>
        /// Unhooks the view model events.
        /// </summary>
        /// <param name="viewModel">The view model.</param>
        private void UnhookViewModelEvents( DriverSettingsViewModel viewModel )
        {
            viewModel.CloseViewRequested -= ViewModel_CloseViewRequested;
        }
        /// <summary>
        /// Unhooks the window events.
        /// </summary>
        /// <param name="window">The window.</param>
        private void UnhookWindowEvents( Window window )
        {
            window.Closed -= Window_Closed;
        }

        #endregion

        #region - Event Handlers

        /// <summary>
        /// Handles the CloseViewRequested event of the ViewModel.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="CloseViewRequestedEventArgs" /> instance containing the event data.</param>
        private void ViewModel_CloseViewRequested( object sender, CloseViewRequestedEventArgs e )
        {
            var window = this.Window;
            if ( window == null )
                return;
            window.DialogResult = e.Confirmed;
            window.Close( );
        }
        /// <summary>
        /// Handles the Closed event of the Window.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        private void Window_Closed( object sender, EventArgs e )
        {
            this.Dispose( );
        }

        #endregion

        #endregion

        #region Public

        #region - Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="WindowAdapter" /> class.
        /// </summary>
        /// <param name="window">The window.</param>
        /// <param name="viewModel">The view model.</param>
        /// <param name="ownsViewModel">if set to <c>true</c> if the adapter owns the view model.</param>
        public WindowAdapter( Window window, DriverSettingsViewModel viewModel, bool ownsViewModel = false )
        {
            Guard.ArgumentNotNull( window, "window" );
            Guard.ArgumentNotNull( viewModel, "viewModel" );

            this._ownsViewModel = ownsViewModel;
            this.Window = window;
            this.ViewModel = viewModel;

            this.HookViewModelEvents( viewModel );
            this.HookWindowEvents( window );

            window.DataContext = viewModel;
        }

        #endregion

        #region - Properties

        /// <summary>
        /// Gets the view model.
        /// </summary>
        /// <value>
        /// The view model.
        /// </value>
        public DriverSettingsViewModel ViewModel
        {
            get;
            private set;
        }
        /// <summary>
        /// Gets the window.
        /// </summary>
        /// <value>
        /// The window.
        /// </value>
        public Window Window
        {
            get;
            private set;
        }

        #endregion

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose( )
        {
            if ( this.Window != null )
            {
                this.UnhookWindowEvents( this.Window );
                this.Window.DataContext = null;
                this.Window = null;
            }
            if ( this.ViewModel != null )
            {
                this.UnhookViewModelEvents( this.ViewModel );
                if ( this._ownsViewModel )
                    this.ViewModel.Dispose( );
                this.ViewModel = null;
            }

            GC.SuppressFinalize( this );
        }

        #endregion
    }
}
